package com.hoho.android.usbserial.examples;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.HexDump;
import com.hoho.android.usbserial.util.SerialInputOutputManager;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

public class NewActivity extends AppCompatActivity implements SerialInputOutputManager.Listener {

    private TextView tvPrice;

    private EditText etPrice;

    private String priceStr;

    private String weightStr;

    private BroadcastReceiver broadcastReceiver;

    private static final String INTENT_ACTION_GRANT_USB = BuildConfig.APPLICATION_ID + ".GRANT_USB";

    private UsbManager usbManager;

    private UsbSerialPort usbSerialPort;

    /**
     * 内部包含连接设备
     **/
    private UsbSerialDriver driver;

    /**
     * USB 连接状态
     **/
    private boolean connected = false;

    /**
     * 波特率
     **/
    private final int baudRate = 9600;

    /**
     * 权限相关的属性
     */
    private UsbPermission usbPermission = UsbPermission.Unknown;

    private SerialInputOutputManager usbIoManager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_new);

        usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

        initView();

        // 2. 注册监听
        initReceiver();

        // 3. 加载USB设备
        loadFirstUsbDevice();

        // 4. 连接，如果成功则被动接受消息展示
        connect();
    }

    /**
     * 初始化控件
     */
    private void initView() {
        tvPrice = findViewById(R.id.tv_price);
        etPrice = findViewById(R.id.et_price);
        etPrice.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                priceStr = editable.toString();
            }
        });
    }

    /**
     * 初始化USB驱动
     */
    private void initReceiver() {
        broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (INTENT_ACTION_GRANT_USB.equals(intent.getAction())) {
                    usbPermission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)
                            ? UsbPermission.Granted : UsbPermission.Denied;
                    connect();
                }
            }
        };

        ContextCompat.registerReceiver(this, broadcastReceiver,
                new IntentFilter(INTENT_ACTION_GRANT_USB), ContextCompat.RECEIVER_NOT_EXPORTED);
    }

    /**
     * 获取当前连接的设备数
     */
    void loadFirstUsbDevice() {
        if (usbManager == null){
            status("usbManager is null");
            return;
        }

        UsbSerialProber usbDefaultProber = UsbSerialProber.getDefaultProber();
        UsbSerialProber usbCustomProber = CustomProber.getCustomProber();
        for(UsbDevice device : usbManager.getDeviceList().values()) {
            driver = usbDefaultProber.probeDevice(device);
            if(driver == null) {
                driver = usbCustomProber.probeDevice(device);
            }
            if (driver != null){
                break;
            }
        }
    }

    private void connect() {

        if (connected) {
            status("method connect: already connected !");
            return;
        }

        if (usbManager == null) {
            status("method connect: usbManager is null");
        }

        if (driver == null) {
            status("method connect: no driver for device! error code 183.");
            return;
        }

        UsbDevice device = driver.getDevice();

        if (device == null) {
            status("method connect: device not found! ");
            return;
        }

        if (driver.getPorts() == null || driver.getPorts().isEmpty()) {
            status("method connect: empty port! ");
            return;
        }

        try {
            usbSerialPort = driver.getPorts().get(device.getDeviceId());
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (usbSerialPort == null) {
            status("method connect: usbSerialPort is null! ");
            return;
        }

        UsbDeviceConnection usbConnection ;

        try {
            usbConnection = usbManager.openDevice(driver.getDevice());
        }catch (Exception e){
            e.printStackTrace();
            status("method connect: usbConnection throw exception! ");
            return;
        }

        // 如果没有权限，需要去获取权限才可以
        if (usbConnection == null
                && usbPermission == UsbPermission.Unknown
                && !usbManager.hasPermission(driver.getDevice())) {
            usbPermission = UsbPermission.Requested;
            try {
                int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_MUTABLE : 0;
                Intent intent = new Intent(INTENT_ACTION_GRANT_USB);
                intent.setPackage(getPackageName());
                PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(this, 0, intent, flags);
                usbManager.requestPermission(driver.getDevice(), usbPermissionIntent);
            }catch (Exception e){
                e.printStackTrace();
                status("method connect: request permission error");
            }
            return;
        }
        if (usbConnection == null) {
            if (!usbManager.hasPermission(driver.getDevice())) {
                status("method connect:permission denied");
            } else {
                status("method connect: open failed");
            }
            return;
        }

        try {
            usbSerialPort.open(usbConnection);
            try {
                usbSerialPort.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
            } catch (UnsupportedOperationException e) {
                status("method connect: unsupport setparameters");
            }
            usbIoManager = new SerialInputOutputManager(usbSerialPort, this);
            usbIoManager.start();
            status("method connect: connected");
            connected = true;

        } catch (Exception e) {
            status("method connect: " + e.getMessage());
            disconnect();
        }
    }

    private void disconnect() {
        connected = false;
        if (usbIoManager != null) {
            usbIoManager.setListener(null);
            usbIoManager.stop();
        }
        usbIoManager = null;
        try {
            usbSerialPort.close();
        } catch (IOException ignored) {
            ignored.printStackTrace();
        }
        usbSerialPort = null;
    }

    private void status(String content) {
        runOnUiThread(() -> Toast.makeText(NewActivity.this, content, Toast.LENGTH_SHORT).show());
        Log.e("USB", content);
    }

    /**
     * 接收到数据
     *
     * @param data /
     */
    @Override
    public void onNewData(byte[] data) {
        if (data.length > 0) {
            weightStr = HexDump.dumpHexString(data);
            runOnUiThread(() -> calc(priceStr, weightStr));
        }
    }

    /**
     * 计算最终价格
     *
     * @param priceStr  /
     * @param weightStr /
     */
    private void calc(String priceStr, String weightStr) {
        try {
            String finalPrice
                    = new BigDecimal(priceStr).multiply(new BigDecimal(weightStr)).toString();
            tvPrice.setText(finalPrice);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 连接失败时会调用该方法
     *
     * @param e /
     */
    @Override
    public void onRunError(Exception e) {
        status("connection lost: " + e.getMessage());
        disconnect();
    }

}
